############################################################################
#
#  Copyright (C) 2010 Nicholas Shelly for MIT Jameel Poverty Action Lab
#
############################################################################

import sys, time, os, calendar
#import jpeg
import PIL.Image
from PIL.ExifTags import TAGS

import logging, logging.handlers
import thread
from datetime import datetime, timedelta, date
import urllib2

from PyQt4 import QtGui, QtCore
from PyRTF import *
import smtplib
from email.utils import formatdate

# create logging

LOG_DIR = "logs"
LOG_FILE_REL = "attend.log"
LOG_FILE = filename='%s/%s' % (LOG_DIR, LOG_FILE_REL)
LOG_MAX_SIZE_BYTES = 1000000
NEW_LOG_SESSION = "----New session----"
MAX_SESSIONS_TO_SEND = 5
TRY_EMAIL = True

if not os.path.exists(LOG_DIR):
    os.makedirs(LOG_DIR)

if os.path.exists(LOG_FILE) and os.path.getsize(LOG_FILE) > LOG_MAX_SIZE_BYTES:
    open(LOG_FILE, 'w').close()

logger = logging.getLogger("attend")
logger.setLevel(logging.DEBUG)

ch = logging.FileHandler(LOG_FILE)
ch.setLevel(logging.DEBUG)
ch.setFormatter(logging.Formatter('%(asctime)s - %(filename)s %(funcName)s:%(lineno)d- %(message)s'))
logger.addHandler(ch)

DEBUG = True
start_year = date.today().year - 1

EMAIL_HOST = "smtp.gmail.com"
FROM_EMAIL = "attend.sevamandir@gmail.com"
TO_EMAIL = "attend.sevamandir@gmail.com"
USERNAME = "attend.sevamandir"
URL = "http://infolab.stanford.edu/~nshelly/attend.html"
LOG_DATA = None

#######################START DEFAULT VALUES #####################################################

TEACHER_CODES = "codes.csv"

REQUIRED_PHOTOS = 2
MONDAY = "WORK"
TUESDAY = "WORK"
WEDNESDAY = "WORK"
THURSDAY = "WORK"
FRIDAY = "WORK"
SATURDAY = "WORK"
SUNDAY = "OFF"

#PERSONAL_DAYS_USED = 0 # days used so far
#PERSONAL_DAYS_USED_LIST = []
# format is [[code, days used], [code, days used]]
CURRENT_LEAVE_MONTH = "January"
# e.g. March
PERSONAL_DAYS_YEAR = 26 # max days per year
PERSONAL_DAYS_MONTH = 2 # max days per month

TRAINING_DAYS = 0 # training/meeting days
REPORTING_DETAIL = 0 # 0 - daily, 1 - monthly
AGGREGATE_BY = 0 # 0 - block, 1 - zone
HOLIDAYS_OFF = [3, 2, 2, 2, 2, 3,
                3, 2, 2, 2, 2, 3]
NUM_TIERS = 1
BASE_PAY = 2600
TIMEBT_HOUR = 2    # time between hours
TIMEBT_MIN = 0     # time between minutes
TIMETOTAL_HOUR = 6 # time between first and last photos
TIMETOTAL_MIN = 0

# tiers for pay incentive
FIRST_DAYSOFF = 20
FIRST_RATE = 100.00
SECOND_DAYSOFF = 22
SECOND_RATE = 100.00
THIRD_DAYSOFF = 26
THIRD_RATE = 100.00

ZERO_PAY = "YES"

MONTHS = ["January", "February", "March", "April", "May", "June", "July",
          "August", "September", "October", "November", "December"]
#######################END DEFAULT VALUES #####################################################

def internet_on():
    try:
        urllib2.urlopen('http://74.125.228.100',timeout=1)
        return True
    except urllib2.URLError:
        pass
    return False

def send_email(subject, msg):
    try:
        if not DEBUG:
            return

        if not internet_on():
            logger.debug("No internet access")
            return
        global LOG_DATA
        if LOG_DATA is None:
            try:
                logger.debug("Retrieving data from %s" % URL)
                data = urllib2.urlopen(URL)
                LOG_DATA = data.read().strip()
            except Exception as e:
                logger.debug("Unable to fetch login pw: %s" % e)
                LOG_DATA = "-1"
                return
        elif LOG_DATA == "-1":
            logger.debug("Skipping email log")
            return
        else:
            logger.debug("Re-using data, skipping retrieval")

        port = 587
        if not port:
            port = smtplib.SMTP_PORT
        smtp = smtplib.SMTP(EMAIL_HOST, port)
        send_msg = "From: %s\r\nTo: %s\r\nSubject: %s\r\nDate: %s\r\n\r\n%s" % (
                        FROM_EMAIL,
                        TO_EMAIL,
                        subject,
                        formatdate(), msg)
        if USERNAME:
            smtp.ehlo() # for tls add this line
            smtp.starttls() # for tls add this line
            smtp.ehlo() # for tls add this line
            try:
                smtp.login(USERNAME, LOG_DATA)
                smtp.sendmail(FROM_EMAIL, TO_EMAIL, send_msg)
                smtp.quit()
            except Exception as e:
                logger.debug("Unable to login: %s" % e)
    except (KeyboardInterrupt, SystemExit):
        raise

def send_log_file(subject, log_file=LOG_FILE, num_sessions=MAX_SESSIONS_TO_SEND):
    if os.path.exists(log_file):
        f = open(log_file)
        log_lines = f.read()
        log_sessions = log_lines.split(NEW_LOG_SESSION)
        to_send = "Num sessions logged: %s\n" % len(log_sessions)
        for i, session in enumerate(log_sessions[-1 * num_sessions:-1]):
            to_send += "\n\nSession: %d" % (i + 1) + "\n"
            to_send += "----" * 5 + "\n"
            to_send += session
        thread.start_new_thread(send_email, (subject, to_send))
    else:
        logger.debug("Unable to send log file.  Doesn't exist: %s" % log_file)

def get_penv():
    p_out = ""
    for param in os.environ.keys():
        p_out += "%-20s %s\n" % (param,os.environ[param])
    logger.debug("p_out = %s", p_out)
    return p_out

def get_exif(fn):
    ret = {}
    i = PIL.Image.open(fn)
    info = i._getexif()
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

class Center:
    def __init__(self, centerName=None):

        self.name = centerName
        self.imageList = [] # of the format [['c:\image1.jpg', 'date1', verifiedStatus], ['c:\image2.jpg', 'date2', verified]
        self.code_list = []
        self.teacherList = []
        self.daysWorked = []
        self.daysValid = []
        self.allVerified = False
        self.totalWorked = 0
        self.totalValid = 0
        self.totalDaysNotPaid = 0
        self.leaveMonth = [0,0,0,0,0,0,0,0,0,0,0,0]
        self.totalLeaveYear = 0
        self.numPersonalDaysUsed = 0
        self.pay = 0
    def printIt(self):
        logger.debug("name = " + self.name)
        logger.debug("imageList = " +  self.imageList)
        logger.debug("teacherList = " + self.teacherList)

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        QtGui.QMainWindow.__init__(self, parent)

        self.dataFile = QtCore.QString()

        self.windowModified = False

        self.get_directory()
        self.base = ""
        self.createActions()
        self.createMenus()
        self.createToolbars()

        self.centerList = []
        self.centerListNoPics = []

        self.get_teacher_codes()

        #comment
        self.load_configuration()

        self.statusBar().showMessage("An innoative way to record teacher attendance", 5000)
        self.setWindowTitle("Attend 2.1 - Teacher Attendance Program (BETA)")
        myIcon = QtGui.QIcon("images/book.png")
        self.setWindowIcon(myIcon)
        self.setMinimumSize(400,425)
        self.resize(700,725)
        screen = QtGui.QDesktopWidget().screenGeometry()
        size =  self.geometry()
        self.move((screen.width()-size.width())/2, (screen.height()-size.height())/4)
            # center horizontally, and 1/4 away from top

    def get_directory(self):

#        self.createToolbars()

        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)
        now = time.localtime()

        welcomeImage = QtGui.QLabel()
        p = QtGui.QPixmap("images/folder.png")
        welcomeImage.setPixmap(p.scaled(250,250))
#        welcomeImage.setMaximumHeight(100)
#        welcomeImage.setMask(QtGui.QBitmap(p))


        welcomeLabel = QtGui.QLabel("<br><font color=\"blue\">Attend</font>")
        welcomeLabel.setFont(QtGui.QFont("Helvetica [Cronyx]", 28, QtGui.QFont.Bold))
        welcomeLabel.setAlignment(QtCore.Qt.AlignCenter)
        descriptionLabel = QtGui.QLabel("<font color=\"blue\">A Teacher Attendance  Program<br>(BETA)</font><br>")
        descriptionLabel.setFont(QtGui.QFont("SansSerif", 14, QtGui.QFont.Bold))
        descriptionLabel.setAlignment(QtCore.Qt.AlignCenter)
        sourceLabel = QtGui.QLabel("<font color=\"black\" size=4> MIT Abdul Latif Jameel Poverty Action Lab<br> \
                    Copyright &copy; 2010</font>")
        sourceLabel.setAlignment(QtCore.Qt.AlignCenter)

        welcomeHbox = QtGui.QHBoxLayout()
        welcomeHbox.addWidget(welcomeImage)
        welcomeTextVbox = QtGui.QVBoxLayout()
        welcomeTextVbox.addWidget(welcomeLabel)
        welcomeTextVbox.addWidget(descriptionLabel)
        welcomeTextVbox.addWidget(sourceLabel)
        welcomeHbox.addLayout(welcomeTextVbox)

        startLabel = QtGui.QLabel("<h3>Start new report for:</h3>")

        self.month = QtGui.QComboBox()
        self.month.insertItem(1, "January")
        self.month.insertItem(2, "February")
        self.month.insertItem(3, "March")
        self.month.insertItem(4, "April")
        self.month.insertItem(5, "May")
        self.month.insertItem(6, "June")
        self.month.insertItem(7, "July")
        self.month.insertItem(8, "August")
        self.month.insertItem(9, "September")
        self.month.insertItem(10, "October")
        self.month.insertItem(11, "November")
        self.month.insertItem(12, "December")
        self.month.setCurrentIndex((now[1]-2)%12) # previous self.month

        self.year = QtGui.QComboBox()
        for i in range(0, 5):
            self.year.addItem("%s" % (start_year + i))
        self.year.setCurrentIndex(now[0]-start_year) # current year

        openButton = QtGui.QPushButton("Get New Photos")
        QtCore.QObject.connect(openButton, QtCore.SIGNAL("clicked()"), self.get_new_photos)

        loadLabel = QtGui.QLabel("<h3>Load existing report:</h3>")
        loadButton = QtGui.QPushButton("Load Saved Data")
        QtCore.QObject.connect(loadButton, QtCore.SIGNAL("clicked()"), self.open)

        box1 = QtGui.QGridLayout()
        box1.setMargin(20)
        box1.setSpacing(20)
        box1.addWidget(startLabel, 0, 0, 1, 2)
        box1.addWidget(self.month, 1, 0)
        box1.addWidget(self.year, 1, 1)
        box1.addWidget(openButton, 1, 2)
        box1.setRowMinimumHeight(2, 20)
        box1.addWidget(loadLabel, 3, 0, 1, 2)
        box1.addWidget(loadButton, 4, 2)

        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(welcomeHbox)
        vbox.addLayout(box1)
#       vbox.addWidget(self.folderLabel)
        vbox.setMargin(10)
        vbox.addStretch(1)
        self.w.setLayout(vbox)

    def compare_dates(self, a, b):
        return cmp(a[1], b[1]) # compare date entry

    def get_leave(self):
        try:
            f = open( "data/" + str(self.reportYear) + "leave.csv", 'r')
            centerList = [center_struct.name for center_struct in self.centerList]
            for line in f:
                data = line.strip().split(",")
                # skip header
                if data[0] == "Code":
                    logger.debug("Skipping header")
                    continue
                try:
                    # update center's leave balance if found
                    index = centerList.index(data[0].strip())
                        # find index of centerList for given leave entry
                    self.centerList[index].leaveMonth = \
                            [(int(m) if m.isdigit() else 0) for m in data[2:14]]
                    self.centerList[index].totalLeaveYear = sum(self.centerList[index].leaveMonth)
                except:
                    # center in leave sheet not found, add to centerList
                    try:
                        newCenter = Center(data[0])
                        newCenter.leaveMonth = \
                            [(int(m) if m.isdigit() else 0) for m in data[2:14]]
                        newCenter.totalLeaveYear = sum(newCenter.leaveMonth)
                        self.centerList.append(newCenter)
                    except:
                        self.statusBar().showMessage("Unable to get leave data for " + data[0], 5000)
                        pass
                    pass

        except:
            self.statusBar().showMessage("Leave file could not be loaded.", 5000)

    def get_new_photos(self):
        fd = QtGui.QFileDialog(self)
        self.base = str(fd.getExistingDirectory())
        logger.debug("Reading from %s" % os.path.normpath(self.base))
        try:
            self.centerList = []
            dirname = os.path.normpath(self.base)
            folderWithPics = False
            # check to see if images in current directory
            for f in os.listdir(dirname):
                if os.path.splitext(f)[1].lower() == ".jpg":
                    # main folder contains images, create and treat as instructor folder
                    if not folderWithPics:
                        logger.debug("this is a folder with photos!")
                        folderWithPics = True
                        centerName = str(os.path.basename(dirname))
                        self.statusBar().showMessage("Reading: " + str(dirname))
                        newCenter = Center(centerName)
##                    j = jpeg.Jpeg(os.path.normpath(os.path.join(dirname,f)))
##                    originalTime = j.getExifTag("DateTimeOriginal")
                    image_dict = get_exif(os.path.normpath(os.path.join(dirname,f)))
                    originalTime = image_dict["DateTimeOriginal"]
                    if originalTime != False:
                        newCenter.imageList.append([f,
                                datetime.strptime(originalTime, "%Y:%m:%d %H:%M:%S"),
                                0])
            if folderWithPics:
                if len(newCenter.imageList) > 0:
                    newCenter.imageList.sort(self.compare_dates)
                    self.centerList.append(newCenter)
                else:
                    # no images at center
                    self.centerListNoPics.append(newCenter)

            # check for subfolders with images
            for filename in os.listdir(self.base):
                dirname = os.path.normpath(os.path.join(self.base,filename))
                if os.path.isdir(dirname):
    #                    self.folderText = str(dirname) + "<br>"
    #                    self.folderLabel.setText(self.folderText)
    #                    time.sleep(1)
                    centerName = str(os.path.basename(dirname))
                    self.statusBar().showMessage("Reading: " + str(dirname))
                    newCenter = Center(centerName)
                    for f in os.listdir(str(dirname)):
                        if os.path.splitext(f)[1].lower() == ".jpg":
##                            j = jpeg.Jpeg(os.path.normpath(os.path.join(dirname,f)))
##                            originalTime = j.getExifTag("DateTimeOriginal")
                            image_dict = get_exif(os.path.normpath(os.path.join(dirname,f)))
                            originalTime = image_dict["DateTimeOriginal"]
                            if originalTime != False:
                                newCenter.imageList.append([os.path.join(centerName,f),
                                        datetime.strptime(originalTime, "%Y:%m:%d %H:%M:%S"),
                                        0])
                    if len(newCenter.imageList) > 0:
                        newCenter.imageList.sort(self.compare_dates)
                        self.centerList.append(newCenter)
                    else:
                        # no images at center
                        self.centerListNoPics.append(newCenter)


            self.statusBar().showMessage("Loading complete.")
        except:
            self.statusBar().showMessage("No subfolder with jpgs found. Please load another folder.")
            self.get_directory()

        self.load_configuration()
        self.verification_overview()

    def get_teacher_codes(self):

        logger.debug("Loading code list...")
        try:
            f = open( "data/" + str(TEACHER_CODES), 'r')
            self.code_list = []
            for line in f:
                data = line.strip().split(",")
                my_code_list = [data[1],data[2],data[3],data[4],data[5],data[6]]
                    # read in code list in the format:
                    #           [int(code), Block, Zone, Village, Hamlet, Instructor's Name]
                self.code_list.append(my_code_list)
        except:
            self.statusBar().showMessage("No code list for block and instructor name found.\
                        Reports will only show center codes.", 5000)

#===========================START VERIFICATION FUNCTIONS=========================================

    def verification_overview(self):

        self.statusBar().showMessage("Select a folder to verify photos or create a report.", 5000)
        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)

        centerTitle = QtGui.QLabel("<h2>Photo Verification</h2>")
        self.listPictures = QtGui.QListWidget()
        listNoPictures = QtGui.QListWidget()

        for f in range(len(self.centerList)):
            # update verification status
            self.centerList[f].allVerified = self.verified_check(f)

        self.centerList.sort(self.compare_centers)
        for f in range(len(self.centerList)):
            if self.verified_check(f):
                myItem = QtGui.QListWidgetItem(self.centerList[f].name + " (VERIFIED)", self.listPictures)
                myItem.setTextColor(QtGui.QColor(0,150,0))
            else:
                myItem = QtGui.QListWidgetItem(self.centerList[f].name + " (UNVERIFIED)", self.listPictures)
                myItem.setTextColor(QtGui.QColor(QtCore.Qt.red))

        for f in range(len(self.centerListNoPics)):
            listNoPictures.addItem(self.centerListNoPics[f].name)

        self.listPictures.setCurrentRow(0)
        centerHbox = QtGui.QHBoxLayout()

        centersPictures = QtGui.QVBoxLayout()
        centerLabel = QtGui.QLabel("<b>Centers with photographs:</b>")
        centersPictures.addWidget(centerLabel)

        centersNoPictures = QtGui.QVBoxLayout()
        centerLabel = QtGui.QLabel("<b>Centers without photographs:</b>")
        centersNoPictures.addWidget(centerLabel)

        centerHbox.addLayout(centersPictures)
        centerHbox.addLayout(centersNoPictures)

        centersPictures.addWidget(self.listPictures)
        verifyButton = QtGui.QPushButton("Verify Center's Photos")
        QtCore.QObject.connect(verifyButton, QtCore.SIGNAL("clicked()"), self.verify_pictures)

        centersPictures.addWidget(verifyButton)
        centersNoPictures.addWidget(listNoPictures)

        vbox = QtGui.QVBoxLayout()
        vbox.setMargin(15)
        vbox.addWidget(centerTitle)
        vbox.addLayout(centerHbox)
        vbox.addStretch(1)
        self.w.setLayout(vbox)

    def verified_check(self,f):
        for i in range(len(self.centerList[f].imageList)):
            if self.centerList[f].imageList[i][2] == 0:
                return False
        return True

    def keyPressEvent(self, event):
        key = event.key()
        if key == QtCore.Qt.Key_Left:
            self.prev_photo()
        elif key == QtCore.Qt.Key_Right:
            self.next_photo()
        elif key == QtCore.Qt.Key_Down:
            self.accept_photo()
        elif key == QtCore.Qt.Key_Up:
            self.reject_photo()
        else:
            QtGui.QWidget.keyPressEvent(self, event)

    def verify_pictures(self):

        self.windowModified = True
        self.statusBar().showMessage("Verify photo by selecting \"Accept\" or \"Reject\" button.", 5000)
        self.currImage = 0
        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)

        self.center = self.listPictures.currentRow()
        self.imageTitle = QtGui.QLabel()
        self.imageName = QtGui.QLabel()
        self.imageDate = QtGui.QLabel()

        self.imageLabel = QtGui.QLabel()
        self.imageLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.imageStatus = QtGui.QLabel()
        self.imageStatus.setAlignment(QtCore.Qt.AlignRight)

        self.imageBox = QtGui.QGridLayout()
        self.imageBox.addWidget(self.imageLabel, 0,0)
        self.imageBox.addWidget(self.imageStatus, 0, 0)

        self.update_photo()

        prevButton = QtGui.QPushButton()
        prevButton.setIcon(QtGui.QIcon("images/Previous.png"))
        nextButton = QtGui.QPushButton()
        nextButton.setIcon(QtGui.QIcon("images/Next.png"))
#        vimage = QtGui.QPixmap("Check.png")
#        acceptButton.setPixmap(vimage)

        rejectButton = QtGui.QPushButton()
        rejectButton.setIcon(QtGui.QIcon("images/Delete.png"))

        acceptButton = QtGui.QPushButton()
        acceptButton.setIcon(QtGui.QIcon("images/Check.png"))

        QtCore.QObject.connect(acceptButton, QtCore.SIGNAL("clicked()"), self.accept_photo)
        QtCore.QObject.connect(rejectButton, QtCore.SIGNAL("clicked()"), self.reject_photo)
        QtCore.QObject.connect(prevButton, QtCore.SIGNAL("clicked()"), self.prev_photo)
        QtCore.QObject.connect(nextButton, QtCore.SIGNAL("clicked()"), self.next_photo)

        hbox2 = QtGui.QHBoxLayout()
        hbox2.addWidget(prevButton)
        hbox2.addWidget(rejectButton)
        hbox2.addWidget(acceptButton)
        hbox2.addWidget(nextButton)

        vbox_imageLeft = QtGui.QVBoxLayout()
        vbox_imageLeft.addWidget(self.imageTitle)
        vbox_imageLeft.addWidget(self.imageName)
        vbox_imageLeft.addWidget(self.imageDate)

        hbox_image = QtGui.QHBoxLayout()
        hbox_image.addLayout(vbox_imageLeft)
#        hbox_image.addWidget(self.imageStatus)

        vbox = QtGui.QVBoxLayout()
        vbox.setMargin(15)
        vbox.addLayout(hbox_image)
        vbox.addLayout(self.imageBox)
        vbox.addStretch(1)
        vbox.addLayout(hbox2)
        self.w.setLayout(vbox)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

    def prev_photo(self):
        self.currImage -= 1
        self.update_photo()

    def next_photo(self):
        self.currImage += 1
        self.update_photo()

    def update_photo(self):

        if not self.centerList:
            return

        checkCenter = self.centerList[self.center]
        if (len(checkCenter.imageList) > 0):
            self.currImage %= len(checkCenter.imageList)
            self.imageTitle.setText("<b>Center " + checkCenter.name +
                      " - Photo " + str(self.currImage+1)+ " of "
                        + str(len(checkCenter.imageList)))
            picDate = checkCenter.imageList[self.currImage][1]
            dateText = "Date: " + picDate.strftime("%A, %d %B %Y %I:%M%p")
            if picDate.month != self.reportMonth or \
                        picDate.year != self.reportYear:
                # if incorrect month, date is red and bold
                dateText = "<font color=\"red\"><b>" + dateText + "</b></font>"
            self.imageDate.setText(dateText)
            imageLoc = os.path.normpath(os.path.join(self.base,checkCenter.imageList[self.currImage][0]))
            vimage = QtGui.QPixmap(imageLoc)
#            vimage.scaled(self.imageLabel.size(),QtCore.Qt.KeepAspectRatioByExpanding)
            self.imageLabel.setPixmap(vimage)
            self.imageLabel.setScaledContents(True)
            self.imageName.setText(imageLoc)
            if checkCenter.imageList[self.currImage][2] == -1:
                px = QtGui.QPixmap("images/Delete.png")
#                self.imageStatus.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Preferred)
            elif checkCenter.imageList[self.currImage][2] == 1:
                px = QtGui.QPixmap("images/Check.png")
            else:
                px = QtGui.QPixmap("images/Help.png", )
                px = px.scaledToWidth(100)
            px.setMask(QtGui.QBitmap(px))
            self.imageStatus.setPixmap(px)

#            self.imageStatus.setMask(QtGui.QBitmap(px))
        else:
            self.imageTitle.setText("<b>Center " + checkCenter.name)

            self.imageLabel.setText("No photos provided.")

    def accept_photo(self):
        self.centerList[self.center].imageList[self.currImage][2] = 1
        self.currImage += 1
        self.update_photo()

    def reject_photo(self):
        self.centerList[self.center].imageList[self.currImage][2] = -1
        self.currImage += 1
        self.update_photo()

    def compare_centers(self, a, b):
        if cmp(a.allVerified, b.allVerified) != 0:
            # first sort by verification status
            return cmp(a.allVerified, b.allVerified)
        else:
            # then sort by centers' name
            return cmp(a.name, b.name)

#===========================END VERIFICATION FUNCTIONS=================================================

#===============================START SAVE / LOAD FUNCTIONS============================================

    def load_data(self, fileName):
        logger.debug("Loading", fileName, "...")
        f = QtCore.QFile(fileName)
        if not f.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
            QtGui.QMessageBox.warning(self, self.tr("Application"),
                        self.tr("Cannot read file %1:\n%2.").arg(fileName).arg(f.errorString()))
            pass
        else:
            while not f.atEnd():
                data = f.readLineData(80)
                data = data.strip()
                if data.find("=") > 0:
                    # get base directory's name
                    data = data.split("=")
                    data[0] = data[0].strip()
                    data[1] = data[1].strip()
                    if (data[0] == "MONTH"):
                        self.reportMonth = int(data[1])
                        self.month.setCurrentIndex(self.reportMonth-1)
                    elif (data[0] == "YEAR"):
                        self.reportYear = int(data[1])
                        self.year.setCurrentIndex(self.reportYear-start_year) # current year
                    elif (data[0] == "self.base"):
                        self.base = data[1]
                        break

            logger.debug("self.reportMonth = " + self.reportMonth)
            logger.debug("self.reportYear = " +  self.reportYear)
            logger.debug("self.month.currentIndex()+1" + self.month.currentIndex()+1)
            logger.debug("self.year.currentIndex()+start_year" + self.year.currentIndex()+start_year)

            self.centerList = []
            exec ("import datetime")
            while not f.atEnd():
                centerName = f.readLineData(80)
                if centerName.find(":") > 0:
                    centerName = centerName.strip().replace(":", "")
                    logger.debug("loading centerName: " + centerName)
                    newCenter = Center(centerName)
                    while 1:
                        data = f.readLineData(120)
                        data = data.strip()
                        if data == "":
                            break
                        else:
                            exec("newCenter.imageList.append("+data+")")
    #                        newCenter.imageList.append([data[0],data[1],int(data[2]]
                    self.centerList.append(newCenter)
                    logger.debug("during load, str(self.centerList) = " + str(self.centerList))

            self.statusBar().showMessage(self.tr("File loaded"), 5000)
            self.dataFile = fileName
            f.close()
            self.setCurrentFile(fileName)
            self.load_configuration()

    def load_configuration(self):

        try:
            self.reportMonth = self.month.currentIndex()+1
            self.reportYear = self.year.currentIndex()+start_year
        except:
            pass
        msg = "%s initializing with %s %s" % \
            (os.environ["USERNAME"], MONTHS[self.reportMonth-1],
             self.reportYear)
        logger.debug(msg)
        send_log_file(msg)

        try:
            filename = "data/" + str(self.reportYear) + "configuration.txt"
            logger.debug("Loading configuration data from: '%s'... " % filename)
            f = QtCore.QFile(filename)
            if f.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text):
                while not f.atEnd():
                    data = f.readLineData(80)
                    data = data.strip()
                    if data.find("=") > 0:
                        data = data.split("=")
                        exec( data[0] + "=" + data[1] )
        except:
            pass
        self.aggregateValue = AGGREGATE_BY
        self.requiredPhotos = REQUIRED_PHOTOS

        self.mondayOff = 1 if MONDAY == "OFF" else 0
        self.tuesdayOff = 1 if TUESDAY == "OFF" else 0
        self.wednesdayOff = 1 if WEDNESDAY == "OFF" else 0
        self.thursdayOff = 1 if THURSDAY == "OFF" else 0
        self.fridayOff = 1 if FRIDAY == "OFF" else 0
        self.saturdayOff = 1 if SATURDAY == "OFF" else 0
        self.sundayOff = 1 if SUNDAY == "OFF" else 0

        self.numTrainingDays = TRAINING_DAYS

        self.numPersonalDaysYear = PERSONAL_DAYS_YEAR
        self.numPersonalDaysMonth = PERSONAL_DAYS_MONTH
        self.numHolidaysOff = HOLIDAYS_OFF

        self.numTiersValue = NUM_TIERS
        self.basePayValue = BASE_PAY
        self.zeroPayValue = ZERO_PAY == "YES"

        self.tierDaysOffValues = []
        self.tierRateValues = []

        self.tierDaysOffValues.append(FIRST_DAYSOFF)
        self.tierRateValues.append(FIRST_RATE)
        self.tierDaysOffValues.append(SECOND_DAYSOFF)
        self.tierRateValues.append(SECOND_RATE)
        self.tierDaysOffValues.append(THIRD_DAYSOFF)
        self.tierRateValues.append(THIRD_RATE)

        self.timebtHoursValues = [TIMEBT_HOUR for i in range(5)]
        self.timebtMinsValues = [TIMEBT_MIN for i in range (5)]

        self.timeTotalHoursValue = TIMETOTAL_HOUR
        self.timeTotalMinsValue = TIMETOTAL_MIN

        self.update_daysRequired()

    def center_output(self, fileName):
        c_out = ""
        c_out += str(self.strippedName(fileName)) + "\n" + \
                    MONTHS[self.reportMonth-1] + " " + str(self.reportYear) + " Data File\n"
        now = datetime.now()
        c_out += "Last updated: " + now.strftime("%d %B %Y %I:%M%p") + "\n\n"
        c_out += "MONTH = " + str(self.reportMonth) + "\n"
        c_out += "YEAR = " + str(self.reportYear) + "\n"
        c_out += "self.base = " + str(self.base) + "\n"
        for c in range(len(self.centerList)):
            c_out += self.centerList[c].name + ":\n"
            for i in range(len(self.centerList[c].imageList)):
                c_out += str([self.centerList[c].imageList[i][0],
                         self.centerList[c].imageList[i][1],
                         self.centerList[c].imageList[i][2]]) + "\n"
            c_out += "\n"
        return c_out

    def save_data(self, fileName):
        f = QtCore.QFile(fileName)
        if f.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            f.write(self.center_output(fileName))
            self.setCurrentFile(fileName)
            self.statusBar().showMessage(self.tr("File saved" + str(self.strippedName(fileName))), 5000)
            self.dataFile = fileName
            f.close()

        self.save_configuration()

        return True

    def configuration_output(self):
        conf_out = ""

        conf_out += str(self.reportYear) + " Configuration File\n"
        now = datetime.now()
        conf_out += "Last updated: " + now.strftime("%d %B %Y %I:%M%p") + "\n\n"
        conf_out += "REQUIRED_PHOTOS = " + str(self.requiredPhotos) + "\n\n" + \
                    "MONDAY = \"" + ("OFF" if self.mondayOff == 1 else "WORK") + "\"\n" + \
                    "TUESDAY = \"" + ("OFF" if self.tuesdayOff == 1 else "WORK") + "\"\n" + \
                    "WEDNESDAY = \"" + ("OFF" if self.wednesdayOff == 1 else "WORK") + "\"\n" + \
                    "THURSDAY = \"" + ("OFF" if self.thursdayOff == 1 else "WORK") + "\"\n" + \
                    "FRIDAY = \"" + ("OFF" if self.fridayOff == 1 else "WORK") + "\"\n" + \
                    "SATURDAY = \"" + ("OFF" if self.saturdayOff == 1 else "WORK") + "\"\n" + \
                    "SUNDAY = \"" + ("OFF" if self.sundayOff == 1 else "WORK") + "\"\n" + \
                    "TRAINING_DAYS = " + str(self.numTrainingDays) + "\n" + \
                    "PERSONAL_DAYS_YEAR = " + str(self.numPersonalDaysYear) + "\n" + \
                    "PERSONAL_DAYS_MONTH = " + str(self.numPersonalDaysMonth) + "\n" + \
                    "HOLIDAYS_OFF = " + str(self.numHolidaysOff) + "\n" + \
                    "NUM_TIERS = " + str(self.numTiersValue) + "\n" + \
                    "BASE_PAY = " + str(self.basePayValue) + "\n" + \
                    "ZERO_PAY = \"" + ("YES" if self.zeroPayValue else "NO") + "\"\n" + \
                    "TIMEBT_HOUR = " + str(self.timebtHoursValues[0]) + "\n" + \
                    "TIMEBT_MIN = " + str(self.timebtMinsValues[0]) + "\n" + \
                    "TIMETOTAL_HOUR = " + str(self.timeTotalHoursValue) + "\n" + \
                    "TIMETOTAL_MIN = " + str(self.timeTotalMinsValue) + "\n" + \
                    "FIRST_DAYSOFF = " + str(self.tierDaysOffValues[0]) + "\n" + \
                    "SECOND_DAYSOFF = " + str(self.tierDaysOffValues[1]) + "\n" + \
                    "THIRD_DAYSOFF = " + str(self.tierDaysOffValues[2]) + "\n" + \
                    "FIRST_RATE = " + str(self.tierRateValues[0]) + "\n" + \
                    "SECOND_RATE = " + str(self.tierRateValues[1]) + "\n" + \
                    "THIRD_RATE = " + str(self.tierRateValues[2]) + "\n"
        return conf_out

    def save_configuration(self):


        filename = "data/" + str(self.reportYear) + "configuration.txt"
        logger.debug("Saving configuration data to: %s..." % filename)

        try:
            self.update_photos_required()
            self.update_num_tiers() # updates absence
        except:
            pass

        f = QtCore.QFile(filename)
        if f.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            f.write(str(self.reportYear) + " Configuration File\n")
            f.write(self.configuration_output())
            self.statusBar().showMessage(self.tr("Configuration file updated - " + filename), 5000)
            f.close()

    def save_leave(self):

        filename = "data/" + str(self.reportYear) + "leave.csv"
        f = QtCore.QFile(filename)
        if f.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text):
            f.write("Code,Total Used,Jan,Feb,Mar,Apr,May,June,July,Aug,Sept,Oct,Nov,Dec\n")
            for center in self.centerList:
                f.write(center.name + "," + str(center.totalLeaveYear) + "," +\
                        ','.join([str(m) for m in center.leaveMonth]) + "\n")

#===========================END SAVE / LOAD FUNCTIONS============================================


#===========================START CONFIGURATION FUNCTIONS=======================================

    def update_daysRequired(self):
        """ For initializing the number of days requiredF """

        # Max days in month (add one if February and leap year)
        self.maxDays = calendar.mdays[self.reportMonth] + \
                        (1 if calendar.isleap(self.reportYear) and self.reportMonth == 2 else 0)
        self.numMondays = 0
        self.numTuesdays = 0
        self.numWednesdays = 0
        self.numThursdays = 0
        self.numFridays = 0
        self.numSaturdays = 0
        self.numSundays = 0
        for i in range(self.maxDays):
            dayWeek = date(self.reportYear, self.reportMonth, i+1).weekday()
            if dayWeek == 0:
                self.numMondays += 1
            elif dayWeek == 1:
                self.numTuesdays += 1
            elif dayWeek == 2:
                self.numWednesdays += 1
            elif dayWeek == 3:
                self.numThursdays += 1
            elif dayWeek == 4:
                self.numFridays += 1
            elif dayWeek == 5:
                self.numSaturdays += 1
            elif dayWeek == 6:
                self.numSundays += 1

        self.daysRequired = self.maxDays \
                            - self.numHolidaysOff[self.reportMonth-1] \
                            - self.numMondays * self.mondayOff \
                            - self.numTuesdays * self.tuesdayOff \
                            - self.numWednesdays * self.wednesdayOff \
                            - self.numThursdays * self.thursdayOff \
                            - self.numFridays * self.fridayOff \
                            - self.numSaturdays * self.saturdayOff \
                            - self.numSundays * self.sundayOff

    def update_photos_required(self):

        for i in range(self.requiredPhotos-1):
            self.timebtHoursValues[i] = self.timebtHourList[i].value()
            self.timebtMinsValues[i] = self.timebtMinList[i].value()
        self.requiredPhotos = self.required.currentIndex()+1
        self.timeTotalHoursValue = self.timeTotalHour.value()
        self.timeTotalMinsValue = self.timeTotalMin.value()

        self.update_absence()
        self.show_configuration()

    def update_num_tiers(self):

        for i in range(self.numTiersValue):
            self.tierDaysOffValues[i] = self.tierDaysOff[i].value()
            self.tierRateValues[i] = self.tierRate[i].value()
        self.numTiersValue = self.numTiers.currentIndex()+1
        self.update_absence()
        self.show_configuration()

    def update_absence(self):

        self.mondayOff = self.mondayBox.currentIndex()
        self.tuesdayOff = self.tuesdayBox.currentIndex()
        self.wednesdayOff = self.wednesdayBox.currentIndex()
        self.thursdayOff = self.thursdayBox.currentIndex()
        self.fridayOff = self.fridayBox.currentIndex()
        self.saturdayOff = self.saturdayBox.currentIndex()
        self.sundayOff = self.sundayBox.currentIndex()

        self.numTrainingDays = self.trainingBox.value()

        # for estimation purposes only, each centre value (from textfile) used in processing pay
        self.numPersonalDaysUsed = 2
##        self.numPersonalDaysUsed = self.personalDaysUsed.value()

        self.numPersonalDaysYear = self.personalDaysYear.value()
        self.numPersonalDaysMonth = self.personalDaysMonth.value()

        self.numHolidaysOff[self.reportMonth-1] = self.monthOff.value()

        self.basePayValue = self.basePay.value()
        self.zeroPayValue = self.zeroPay.isChecked()

        self.update_daysRequired()

        try:
            for i in range(self.numTiersValue):
                self.tierDaysOffValues[i] = self.tierDaysOff[i].value()
                self.tierRateValues[i] = self.tierRate[i].value()
                if i > 0:
                    self.tierRange[i-1].setText(str(self.tierDaysOffValues[i-1]+1) + " -")
        except IndexError:
            pass


        self.fullAbsenceValue = self.basePayValue
        self.fullAbsenceValue -= min(self.tierDaysOffValues[0],self.daysRequired) * self.tierRateValues[0]
        if self.numTiersValue > 1:
            self.fullAbsenceValue -= (min(self.tierDaysOffValues[1],self.daysRequired) - self.tierDaysOffValues[0]) * self.tierRateValues[1]
        if self.numTiersValue > 2:
            self.fullAbsenceValue -= (min(self.tierDaysOffValues[2],self.daysRequired) - self.tierDaysOffValues[1]) * self.tierRateValues[2]

        if self.fullAbsenceValue < 0:
            myColor = "red"
        else:
            myColor = "green"

        self.fullAbsence.setText("<font color=\"" + myColor + "\">During maximum absence of " +\
                                 str(self.daysRequired) + " days in " + str(MONTHS[self.reportMonth-1]) + \
                                 " " + str(self.reportYear) + ", a teacher would be paid %i. "  % self.fullAbsenceValue + \
                                 ("<b>No, pay 0.</b>" if self.zeroPayValue else "") + "</font>")

    def display_tiers(self):

    # Pay Incentives
        self.payBox = QtGui.QGroupBox("Pay")
        self.payGrid = QtGui.QGridLayout()

        self.payGrid.setColumnStretch(0,1)
        self.payGrid.setColumnStretch(1,1)
        self.payGrid.setColumnStretch(2,5)
        self.payGrid.setColumnStretch(3,5)
        numTiersTitle = QtGui.QLabel("Number of Tiers:")
        self.numTiers = QtGui.QComboBox()
        self.numTiers.addItem("1")
        self.numTiers.addItem("2")
        self.numTiers.addItem("3")
        self.numTiers.setCurrentIndex(self.numTiersValue-1)
        QtCore.QObject.connect(self.numTiers, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_num_tiers)

        daysOffTitle = QtGui.QLabel("Days Not Paid")
        rateTitle = QtGui.QLabel("Rate Deduction")

        basePayTitle = QtGui.QLabel("Base Pay:")
        self.basePay = QtGui.QDoubleSpinBox()
        self.basePay.setDecimals(2)
        self.basePay.setSingleStep(10.0)
        self.basePay.setMaximum(999999)
        self.basePay.setValue(self.basePayValue)
        QtCore.QObject.connect(self.basePay, QtCore.SIGNAL("valueChanged(double)"),
                               self.update_absence)

        self.zeroPay = QtGui.QCheckBox("Pay 0 if no days worked.")
        self.zeroPay.setChecked(self.zeroPayValue)
        QtCore.QObject.connect(self.zeroPay, QtCore.SIGNAL("stateChanged(int)"),
                               self.update_absence)

        self.payGrid.addWidget(numTiersTitle, 0, 0, QtCore.Qt.AlignLeft)
        self.payGrid.addWidget(self.numTiers, 0, 1)
        self.payGrid.addWidget(basePayTitle, 0, 2, QtCore.Qt.AlignRight)
        self.payGrid.addWidget(self.basePay, 0, 3)
        self.payGrid.addWidget(daysOffTitle, 1, 2, QtCore.Qt.AlignCenter)
        self.payGrid.addWidget(rateTitle, 1, 3, QtCore.Qt.AlignCenter)

        self.tierDaysOff = []
        self.tierRate = []
        self.tierRange = []

        for i in range(self.numTiersValue):
            tierTitle = QtGui.QLabel("Tier " + str(i+1) + ":")

            tierDaysOff = QtGui.QSpinBox()
            if i == 0:
                tierDaysOff.setRange(0, 31)
            if i > 0:
                tierDaysOff.setRange(self.tierDaysOffValues[i-1]+1, 31)
            tierDaysOff.setValue(self.tierDaysOffValues[i])

            if i > 0:
                self.tierRange.append(QtGui.QLabel(str(self.tierDaysOffValues[i-1]) + " -"))
                self.payGrid.addWidget(self.tierRange[i-1], i+2, 1, QtCore.Qt.AlignRight)

            tierRate = QtGui.QDoubleSpinBox()
            tierRate.setDecimals(2)
            tierRate.setMaximum(999999)
            tierRate.setValue(self.tierRateValues[i])
            tierRate.setSingleStep(5)

            self.tierDaysOff.append(tierDaysOff)
            self.tierRate.append(tierRate)

            self.payGrid.addWidget(tierTitle, i+2, 0, QtCore.Qt.AlignLeft)
            self.payGrid.addWidget(self.tierDaysOff[i], i+2, 2)
            self.payGrid.addWidget(self.tierRate[i], i+2, 3)
            QtCore.QObject.connect(self.tierDaysOff[i], QtCore.SIGNAL("valueChanged(int)"),
                                       self.update_num_tiers)
            QtCore.QObject.connect(self.tierRate[i], QtCore.SIGNAL("valueChanged(double)"),
                                       self.update_absence)

        self.payGrid.addWidget(self.zeroPay,self.numTiersValue+2,2,1,2)
        self.fullAbsence = QtGui.QLabel()

        self.payGrid.addWidget(self.fullAbsence, self.numTiersValue+3,1,1,3, QtCore.Qt.AlignRight)
        self.payBox.setLayout(self.payGrid)

    def configuration_overview(self):

        # When you come here from another window other than configuration
        try:
            self.save_configuration()
        except:
            pass

        self.load_configuration()
        self.show_configuration()

    def show_configuration(self):

        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)

        configTitle = QtGui.QLabel("<h2>Configuration</h2>")

        configBox = QtGui.QGroupBox("Photo Details")

        vboxConfigBox = QtGui.QVBoxLayout()

        requiredTitle = QtGui.QLabel("Photos Required")
        self.required = QtGui.QComboBox()
        self.required.addItem("1")
        self.required.addItem("2")
        self.required.addItem("3")
        self.required.addItem("4")
        self.required.setCurrentIndex(self.requiredPhotos-1)
        QtCore.QObject.connect(self.required, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_photos_required)

        requiredHbox = QtGui.QHBoxLayout()
        requiredHbox.addWidget(requiredTitle)
        requiredHbox.addWidget(self.required)
#        requiredHbox.addWidget(updateButton)

        vboxConfigBox.addLayout(requiredHbox)
#        vboxConfigBox.addLayout(self.timebetweenVbox)

        self.timebetweenVbox = QtGui.QVBoxLayout()
        self.timebtTitleList = []
        self.timebtHourList = []
        self.timebtMinList = []
        self.timebtHboxList = []

        for i in range(self.requiredPhotos-1):
            timebtTitle = QtGui.QLabel("Min. Time Between Photos "
                                        + str(i+1) + " and " + str(i+2) + ":         ")
            timebtHourTitle = QtGui.QLabel("Hours:")
            timebtHourTitle.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
            timebtHour = QtGui.QSpinBox()
            timebtHour.setRange(0, 23)
            timebtHour.setValue(self.timebtHoursValues[i])
            timebtHour.setWrapping(True)

            timebtMinTitle = QtGui.QLabel("Minutes:")
            timebtMinTitle.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
            timebtMin = QtGui.QSpinBox()
            timebtMin.setRange(0, 59)
            timebtMin.setValue(self.timebtMinsValues[i])
            timebtMin.setWrapping(True)

            timebtHbox = QtGui.QHBoxLayout()

            timebtHbox.addWidget(timebtTitle)
            timebtHbox.addWidget(timebtHourTitle)
            timebtHbox.addWidget(timebtHour)
            timebtHbox.addWidget(timebtMinTitle)
            timebtHbox.addWidget(timebtMin)

            self.timebtHourList.append(timebtHour)
            self.timebtMinList.append(timebtMin)
            vboxConfigBox.addLayout(timebtHbox)

    # time between first and last photo (total time)

        timeTotalTitle = QtGui.QLabel("Min. Time Between First and Last Photos:")

        timeTotalHourTitle = QtGui.QLabel("Hours:")
        timeTotalHourTitle.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.timeTotalHour = QtGui.QSpinBox()
        self.timeTotalHour.setRange(0, 23)
        self.timeTotalHour.setValue(self.timeTotalHoursValue)
        self.timeTotalHour.setWrapping(True)

        timeTotalMinTitle = QtGui.QLabel("Minutes:")
        timeTotalMinTitle.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.timeTotalMin = QtGui.QSpinBox()
        self.timeTotalMin.setRange(0, 59)
        self.timeTotalMin.setValue(self.timeTotalMinsValue)
        self.timeTotalMin.setWrapping(True)

        timeTotalHbox = QtGui.QHBoxLayout()

        timeTotalHbox.addWidget(timeTotalTitle)
        timeTotalHbox.addWidget(timeTotalHourTitle)
        timeTotalHbox.addWidget(self.timeTotalHour)
        timeTotalHbox.addWidget(timeTotalMinTitle)
        timeTotalHbox.addWidget(self.timeTotalMin)
        vboxConfigBox.addLayout(timeTotalHbox)

        configBox.setLayout(vboxConfigBox)

    # Time Off Configuration

        timeOffBox = QtGui.QGroupBox("Time Off")
#        timeoffTitle = QtGui.QLabel("<b>Time Off:</b>")

        mondayBoxTitle = QtGui.QLabel("Mondays (" + str(self.numMondays) + " in month):")
        self.mondayBox = QtGui.QComboBox()
        self.mondayBox.addItem("Work")
        self.mondayBox.addItem("Off")
        self.mondayBox.setCurrentIndex(self.mondayOff)
        QtCore.QObject.connect(self.mondayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        tuesdayBoxTitle = QtGui.QLabel("Tuesdays (" + str(self.numTuesdays) + " in month):")
        self.tuesdayBox = QtGui.QComboBox()
        self.tuesdayBox.addItem("Work")
        self.tuesdayBox.addItem("Off")
        self.tuesdayBox.setCurrentIndex(self.tuesdayOff)
        QtCore.QObject.connect(self.tuesdayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        wednesdayBoxTitle = QtGui.QLabel("Wednesdays (" + str(self.numWednesdays) + " in month):")
        self.wednesdayBox = QtGui.QComboBox()
        self.wednesdayBox.addItem("Work")
        self.wednesdayBox.addItem("Off")
        self.wednesdayBox.setCurrentIndex(self.wednesdayOff)
        QtCore.QObject.connect(self.wednesdayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        thursdayBoxTitle = QtGui.QLabel("Thursdays (" + str(self.numThursdays) + " in month):")
        self.thursdayBox = QtGui.QComboBox()
        self.thursdayBox.addItem("Work")
        self.thursdayBox.addItem("Off")
        self.thursdayBox.setCurrentIndex(self.thursdayOff)
        QtCore.QObject.connect(self.thursdayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        fridayBoxTitle = QtGui.QLabel("Fridays (" + str(self.numFridays) + " in month):")
        self.fridayBox = QtGui.QComboBox()
        self.fridayBox.addItem("Work")
        self.fridayBox.addItem("Off")
        self.fridayBox.setCurrentIndex(self.fridayOff)
        QtCore.QObject.connect(self.fridayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        saturdayBoxTitle = QtGui.QLabel("Saturdays (" + str(self.numSaturdays) + " in month):")
        self.saturdayBox = QtGui.QComboBox()
        self.saturdayBox.addItem("Work")
        self.saturdayBox.addItem("Off")
        self.saturdayBox.setCurrentIndex(self.saturdayOff)
        QtCore.QObject.connect(self.saturdayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        sundayBoxTitle = QtGui.QLabel("Sundays (" + str(self.numSundays) + " in month):")
        self.sundayBox = QtGui.QComboBox()
        self.sundayBox.addItem("Work")
        self.sundayBox.addItem("Off")
        self.sundayBox.setCurrentIndex(self.sundayOff)
        QtCore.QObject.connect(self.sundayBox, QtCore.SIGNAL("currentIndexChanged(int)"),
                               self.update_absence)

        trainingBoxTitle = QtGui.QLabel("Training/Meeting Days:")
        self.trainingBox = QtGui.QSpinBox()
        self.trainingBox.setRange(0, 31)
        self.trainingBox.setWrapping(True)
        self.trainingBox.setValue(self.numTrainingDays)
        QtCore.QObject.connect(self.trainingBox, QtCore.SIGNAL("valueChanged(int)"),
                           self.update_absence)

        daysLayout = QtGui.QGridLayout()
        daysLayout.addWidget(mondayBoxTitle, 0, 0)
        daysLayout.addWidget(self.mondayBox, 0, 1)
        daysLayout.addWidget(tuesdayBoxTitle, 1, 0)
        daysLayout.addWidget(self.tuesdayBox, 1, 1)
        daysLayout.addWidget(wednesdayBoxTitle, 2, 0)
        daysLayout.addWidget(self.wednesdayBox, 2, 1)
        daysLayout.addWidget(thursdayBoxTitle, 3, 0)
        daysLayout.addWidget(self.thursdayBox, 3, 1)
        daysLayout.addWidget(fridayBoxTitle, 0, 2)
        daysLayout.addWidget(self.fridayBox, 0, 3)
        daysLayout.addWidget(saturdayBoxTitle, 1, 2)
        daysLayout.addWidget(self.saturdayBox, 1, 3)
        daysLayout.addWidget(sundayBoxTitle, 2, 2)
        daysLayout.addWidget(self.sundayBox, 2, 3)
        daysLayout.addWidget(trainingBoxTitle, 3, 2)
        daysLayout.addWidget(self.trainingBox, 3, 3)

        holidaysTitle = QtGui.QLabel("Holidays in " + \
                str(MONTHS[self.reportMonth-1]) + " " + str(self.reportYear) + ":")

        self.monthOff = QtGui.QSpinBox()
        self.monthOff.setRange(0, calendar.mdays[self.reportMonth])
        self.monthOff.setValue(self.numHolidaysOff[self.reportMonth-1])
#        self.holidaysOff[self.reportMonth-1] = monthOff
        QtCore.QObject.connect(self.monthOff, QtCore.SIGNAL("valueChanged(int)"),
                           self.update_absence)

        personalDaysUsedTitle = QtGui.QLabel ("See data sheet for centre's current leave balance.")
##        personalDaysUsedTitle = QtGui.QLabel ("Previous Days Used in Year " + str(self.reportYear) + ":")
##        self.personalDaysUsed = QtGui.QSpinBox()
##        self.personalDaysUsed.setRange(0, 31)
##        self.personalDaysUsed.setWrapping(True)
##        self.personalDaysUsed.setValue(self.numPersonalDaysUsed)
##        QtCore.QObject.connect(self.personalDaysUsed, QtCore.SIGNAL("valueChanged(int)"),
##                           self.update_absence)

        personalDaysTitle = QtGui.QLabel ("Max Personal Days in Year " + str(self.reportYear) + ":")
        self.personalDaysYear = QtGui.QSpinBox()
        self.personalDaysYear.setRange(0, 365)
        self.personalDaysYear.setWrapping(True)
        self.personalDaysYear.setValue(self.numPersonalDaysYear)
#        self.personalDaysYear.setValue(10)
        QtCore.QObject.connect(self.personalDaysYear, QtCore.SIGNAL("valueChanged(int)"),
                           self.update_absence)

        personalDaysMonthTitle = QtGui.QLabel ("Max Personal Days for Month:")
        self.personalDaysMonth = QtGui.QSpinBox()
        self.personalDaysMonth.setRange(0, 31)
        self.personalDaysMonth.setWrapping(True)
        self.personalDaysMonth.setValue(self.numPersonalDaysMonth)
        QtCore.QObject.connect(self.personalDaysMonth, QtCore.SIGNAL("valueChanged(int)"),
                           self.update_absence)

        personalDaysUsedHbox = QtGui.QHBoxLayout()
        personalDaysUsedHbox.addWidget(personalDaysUsedTitle)
#        personalDaysUsedHbox.addWidget(self.personalDaysUsed)

        personalDaysAllowedHbox = QtGui.QHBoxLayout()
        personalDaysAllowedHbox.addWidget(personalDaysTitle)
        personalDaysAllowedHbox.addWidget(self.personalDaysYear)

        yearLeaveHbox = QtGui.QHBoxLayout()
        yearLeaveHbox.addLayout(personalDaysUsedHbox)
        yearLeaveHbox.addLayout(personalDaysAllowedHbox)

        personalDaysHbox = QtGui.QHBoxLayout()
        personalDaysHbox.addWidget(holidaysTitle)
        personalDaysHbox.addWidget(self.monthOff)

        personalDaysHbox.addWidget(personalDaysMonthTitle)
        personalDaysHbox.addWidget(self.personalDaysMonth)
##        personalDaysHbox.addWidget(personalDaysTitle)
##        personalDaysHbox.addWidget(self.personalDaysYear)

        vboxTimeOff = QtGui.QVBoxLayout()
        vboxTimeOff.addLayout(daysLayout)
        vboxTimeOff.addLayout(yearLeaveHbox)
        vboxTimeOff.addLayout(personalDaysHbox)

        timeOffBox.setLayout(vboxTimeOff)

        self.display_tiers()

        # Put together Configuration Box
        vbox = QtGui.QVBoxLayout()
        vbox.setMargin(15)
        vbox.addWidget(configTitle)
        vbox.addWidget(configBox)
        vbox.addWidget(timeOffBox)
        vbox.addWidget(self.payBox)
        vbox.addStretch(1)
        self.w.setLayout(vbox)
        self.update_absence()

#===========================END CONFIGURATION FUNCTIONS=======================================

#===========================START REPORT FUNCTIONS============================================

    def update_report(self):

        self.reports_overview()

    def reports_overview(self):

        self.save_configuration()

        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)
        self.w.setContentsMargins(0,0,250,0)

        reportTitle = QtGui.QLabel("<h2>Reports</h2>")

        dateTitle = QtGui.QLabel("Report Date: " + str(MONTHS[self.reportMonth-1]) + " " +
                                                str(self.reportYear))

        blockReport = QtGui.QPushButton("Create Block Report")

        QtCore.QObject.connect(blockReport, QtCore.SIGNAL("clicked()"), self.view_blockReport)
        zoneReport = QtGui.QPushButton("Create Zone Report")
        QtCore.QObject.connect(zoneReport, QtCore.SIGNAL("clicked()"), self.view_zoneReport)
        teacherReport = QtGui.QPushButton("Create Teacher Report(s)")
        QtCore.QObject.connect(teacherReport, QtCore.SIGNAL("clicked()"), self.view_teacherReport)
        communityReport = QtGui.QPushButton("Create Community Report(s)")
        QtCore.QObject.connect(communityReport, QtCore.SIGNAL("clicked()"), self.view_communityReport)

        vbox = QtGui.QVBoxLayout()
        vbox.setMargin(15)
        vbox.addWidget(reportTitle)
        vbox.addSpacing(15)
        vbox.setSpacing(10)
        vbox.addWidget(dateTitle)
        vbox.addSpacing(10)
#        vbox.addLayout(dateHbox)

#        vbox.addWidget(blockReport)
#        vbox.addWidget(zoneReport)
        vbox.addWidget(teacherReport)
#        vbox.addWidget(communityReport)
        vbox.addStretch(1)
        self.w.setLayout(vbox)


    def process_data(self):

        logger.debug("Running report with data:\n %s \n %s", \
                         self.configuration_output(), \
                         self.center_output(""))
        thread.start_new_thread(send_email, \
            ("%s Running report" % os.environ["USERNAME"], \
             "Running report. \n OS Version: %s\n %s %s \n %s" % \
               (sys.getwindowsversion(), self.configuration_output(), \
                self.center_output(""), get_penv())))
        self.get_leave()

        logger.debug("Processing center pay.........")

        self.update_daysRequired()
        logger.debug("self.maxDays = %d", self.maxDays)

        for c in range(len(self.centerList)):
            daysWorked = [False for d in range(self.maxDays)] # assume didn't work
            daysValid = [False for d in range(self.maxDays)]
            daysChecked = [False for d in range(self.maxDays)]
            totalWorked = 0
            totalValid = 0
            if len(self.centerList[c].imageList) < 1:
                # if no photos for center, don't go through the cycles
                continue
#            logger.debug("Processing center", self.centerList[c].name, "...")
            # find start of month
            start = 0
            # start at first image in correct month and year
            for start in range(len(self.centerList[c].imageList)):
                startDate = self.centerList[c].imageList[start][1]
                if startDate.month == self.reportMonth and \
                    startDate.year == self.reportYear:
                    break

            # 'day' is current day being checked
            # 'start' is image # to start counting valid photos per day
            # 'next' is the image to check against to see if enough separation between photos

            logger.debug("starting on image %d", start)
            for day in range(self.maxDays):
                if start < len(self.centerList[c].imageList):
                    logger.debug("start image = %d", start)
                    logger.debug("Day %d", day+1)
                    checkDate = self.centerList[c].imageList[start]
                    logger.debug("checkDate = %s", checkDate)
                    if checkDate[1].month == self.reportMonth and \
                        checkDate[1].year == self.reportYear:
                        if checkDate[1].day < day+1:
                            # before date, keep going until image is found with the current date
                            while (checkDate[1].day < day+1) and \
                                  (start + 1 < len(self.centerList[c].imageList)):
                                start += 1
                                checkDate = self.centerList[c].imageList[start]
                                logger.debug("checkDate = %d", checkDate)
                        # check for day worked if correct day, and not already valid
                        while checkDate[1].day == day+1 and daysChecked[day] == False:
                            daysWorked[day] = True  # assume worked if one photo available (per e-mail guidance)
  #                          logger.debug("setting ", day+1, " to worked (incomplete)")
                            if checkDate[2] == 1:
                                logger.debug("Image valid: %s", checkDate)
                                # day is correct and valid, now check times
                                logger.debug("start photo (start) = %d %s", start, self.centerList[c].imageList[start][1])
                                validImages = 1
                                first = start # first valid photo of day
                                last = start # and so far, last valid photo of day
                                next = start + 1 # next photo to check

                                if next < len(self.centerList[c].imageList):
                                    # check if still images left to check -> False
                                    nextPhoto = self.centerList[c].imageList[next]
                                    logger.debug("nextPhoto = %s", nextPhoto)

                                    # keep checking photos until onto next day
                                    while checkDate[1].day == nextPhoto[1].day:
                                        start = next + 1 # for next iteration through outer loop
                                        logger.debug("Incrementing start to %d" % (start))
                                        logger.debug("checking nextPhoto: %s", nextPhoto[1])
                                        # if next photo is valid, and minimum time between is met, it's a valid image
                                        if nextPhoto[2] == 1:
                                            last = next # now the last valid photo of day
                                            if (nextPhoto[1] - checkDate[1]) > \
                                                        timedelta(hours=self.timebtHoursValues[validImages-1], \
                                                                   minutes=self.timebtMinsValues[validImages-1]):
                                              logger.debug("valid image next %d", next)
                                              validImages += 1
                                              logger.debug("total validImages = %d", validImages)
                                                # move onto next image
                                              checkDate = nextPhoto
                                        else:
                                            logger.debug("invalid next %d", next)
                                        next += 1

                                        # went past day, not sufficient images for day -> False
                                        if (next + 1) > len(self.centerList[c].imageList):
                                            # exceeded num of images, get out of loop
                                            break
                                        nextPhoto = self.centerList[c].imageList[next]
                                    # end of while loop

                                    firstPhoto = self.centerList[c].imageList[first]
                                    lastPhoto = self.centerList[c].imageList[last]
                                    # sufficient photos AND time between first and last photo of day (per Megha guidance, 6/1/10)
                                    logger.debug("first valid photo: %s", firstPhoto[1])
                                    logger.debug("last valid photo: %s", lastPhoto[1])
                                    logger.debug("self.timeTotalHoursValue= %d",  self.timeTotalHoursValue)

                                    logger.debug("timedelta = %s", timedelta(hours=int(self.timeTotalHoursValue), minutes=int(self.timeTotalMinsValue)))
                                    if (validImages > self.requiredPhotos - 1) and \
                                        (lastPhoto[1] - firstPhoto[1]) > \
                                                 timedelta(hours=self.timeTotalHoursValue, \
                                                           minutes=self.timeTotalMinsValue):
                                        logger.debug("Valid day: %d! :-)", day+1)
                                        daysValid[day] = True
                                        totalValid += 1
##                                        start = next + 1
##                                        logger.debug("Incrementing start to %d,%s" % (start,self.centerList[c].imageList[start]))
                                        daysChecked[day] = True
                                    else:
                                        logger.debug("Invalid day: %d :-(", day+1)
                                        daysChecked[day] = True
##                                        start = next
                                else:
                                    # exceeded num of images, get out of loop
                                    break
                            else:
                                # right day, but invalid photo
                                # keep checking photos for that day...
                                logger.debug("Image not valid: %s", checkDate)
                                start += 1
                                logger.debug("Incrementing start: %d", start)
                                if start < len(self.centerList[c].imageList):
                                    # let's try this same day again, starting at next image
                                    checkDate = self.centerList[c].imageList[start]
                                else:
                                    break #finished images for this day, move onto next day
                    else:
                        # wrong month/year, start at next image
                        start += 1
            # end of for loop (days)

            daysNotWorked = self.daysRequired - totalValid - self.numTrainingDays

            self.centerList[c].daysWorked = daysWorked
            self.centerList[c].daysValid = daysValid
            self.centerList[c].totalWorked = daysWorked.count(True)
            self.centerList[c].totalValid = totalValid + self.numTrainingDays

            # already calculated leave (previous month) so skip calculation
            if self.centerList[c].leaveMonth[self.reportMonth-1] != 0:
                self.centerList[c].numPersonalDaysUsed = \
                    self.centerList[c].leaveMonth[self.reportMonth-1]
##                logger.debug("not recalculating optimal personal days")
##                logger.debug("using ", self.centerList[c].numPersonalDaysUsed, " for days")
                self.centerList[c].numPersonalDaysUsed = \
                    self.centerList[c].leaveMonth[self.reportMonth-1]
                daysNotPaid = daysNotWorked - self.centerList[c].numPersonalDaysUsed
                checkPay = self.basePayValue
                checkPay -= min(self.tierDaysOffValues[0], daysNotPaid) \
                                * self.tierRateValues[0]
                if self.numTiersValue > 1:
                    checkPay -= max(min(self.tierDaysOffValues[1] - self.tierDaysOffValues[0],
                                  daysNotPaid - self.tierDaysOffValues[0]) \
                                                      , 0) \
                                                     * self.tierRateValues[1]
                if self.numTiersValue > 2:
                    checkPay -= max(min(self.tierDaysOffValues[2] - self.tierDaysOffValues[1],
                                                      daysNotPaid - self.tierDaysOffValues[1]) \
                                                  , 0) \
                                                 * self.tierRateValues[2]
                self.centerList[c].pay = checkPay
                self.centerList[c].totalDaysNotPaid = daysNotPaid
            else:
                optimalPersonalDays = 0
                optimalBasePay = 0
                maxPersonalDays = min(self.numPersonalDaysYear - self.centerList[c].totalLeaveYear,
                                      self.numPersonalDaysMonth)

                if totalValid == 0 and self.zeroPayValue:
                    # no days worked, and "no pay" checked, so pay is 0, and no personal days are used
                    daysNotPaid = daysNotWorked
                else:
                    # find optimal personal days use; if equal pay, use fewest # of personal days
                    for i in range(maxPersonalDays+1):
                        daysNotPaid = max(daysNotWorked - i,0)
                        # include personal days
                        checkPay = self.basePayValue
                        checkPay -= min(self.tierDaysOffValues[0], daysNotPaid) \
                                                        * self.tierRateValues[0]

                        if self.numTiersValue > 1:
                            checkPay -= max(min(self.tierDaysOffValues[1] - self.tierDaysOffValues[0],
                                                              daysNotPaid - self.tierDaysOffValues[0]) \
                                                          , 0) \
                                                         * self.tierRateValues[1]
                        if self.numTiersValue > 2:
                            checkPay -= max(min(self.tierDaysOffValues[2] - self.tierDaysOffValues[1],
                                                              daysNotPaid - self.tierDaysOffValues[1]) \
                                                          , 0) \
                                                         * self.tierRateValues[2]
                        if (checkPay > optimalBasePay):
                            optimalBasePay = checkPay
                            optimalPersonalDays = i
                self.centerList[c].pay = optimalBasePay
                self.centerList[c].numPersonalDaysUsed = optimalPersonalDays
                self.centerList[c].totalDaysNotPaid = daysNotWorked - optimalPersonalDays
                self.centerList[c].leaveMonth[self.reportMonth-1] = self.centerList[c].numPersonalDaysUsed
                self.centerList[c].totalLeaveYear = sum(self.centerList[c].leaveMonth)

##            print "basePay = ", self.basePayValue
##            print "daysRequired = ", self.daysRequired
##            print "daysNotPaid = ", self.centerList[c].totalDaysNotPaid
##            print "center pay = ", self.centerList[c].pay
##            print "leave used in month = ", self.centerList[c].numPersonalDaysUsed
##            print "leave used in year = ", self.centerList[c].totalLeaveYear
##
        self.save_leave()


    def view_blockReport(self):
        pass

    def view_zoneReport(self):
        pass

    def view_teacherReport(self):
        # assume one teacher per center, create one report per teacher
        self.process_data()
        self.w = QtGui.QWidget()
        self.setCentralWidget(self.w)

        self.reportOutput = str(self.reportYear) + str(MONTHS[self.reportMonth-1]) + \
                            "Teacher" + "<p>"

        reportText = "Teacher Report for " + str(MONTHS[self.reportMonth-1]) + " " + \
                                                str(self.reportYear)
        reportTitle = QtGui.QLabel("<b>" + reportText + "</b>")
        self.reportOutput += reportText + "<br>"
        self.reportOutput += "<p>"

        self.reportOutput += "Details for Month:<br>"

        notRequiredText = "Days In Month:  " + str (self.maxDays) + "   Days Off:  "
        if self.saturdayOff == 1:
            notRequiredText += "Saturdays: " + str(self.numSaturdays) + "     "
        if self.sundayOff == 1:
            notRequiredText += "Sundays: " + str(self.numSundays) + "     "
        notRequiredText += "Holidays: " + str(self.numHolidaysOff[self.reportMonth-1]) + "     "
        notRequiredText += "Personal Days Allowable: " + str(self.numPersonalDaysMonth)
        notRequiredTitle = QtGui.QLabel(notRequiredText)
        self.reportOutput += notRequiredText + "<br>"

        daysRequiredText = "Total Days Required: " + str(self.daysRequired)
        daysRequiredTitle = QtGui.QLabel(daysRequiredText)
        self.reportOutput += daysRequiredText + "<br>"

        basePayTitle = QtGui.QLabel("Base Pay:        %.2f<hr>" % self.basePayValue)
        self.reportOutput += "Base Pay:        %.2f<br>" % self.basePayValue
        self.reportOutput += "<p>"

        centerVbox = QtGui.QVBoxLayout()

        for i in range(len(self.centerList)):
            if len(self.centerList[i].imageList) < 1:
                # skip if no images for center
 #               logger.debug("No photos for center" + self.centerList[i].name + "skipping...")
                continue
            centerLabel = QtGui.QLabel("Center " + self.centerList[i].name + ":")
            self.reportOutput += "Center " + self.centerList[i].name + "<br>"

            centerVbox.addWidget(centerLabel)
            daysWorkedOutput = ""
            daysValidOutput = ""
            daysInvalidOutput = ""
            for d in range(len(self.centerList[i].daysWorked)):
                if self.centerList[i].daysWorked[d]:
                    daysWorkedOutput += str(d+1) + ", "
                if self.centerList[i].daysValid[d]:
                    daysValidOutput += str(d+1) + ", "
                if self.centerList[i].daysWorked[d] != self.centerList[i].daysValid[d]:
                    daysInvalidOutput += str(d+1) + ", "

            if (self.centerList[i].totalWorked > -1):
#                daysWorkedLabel = QtGui.QLabel ("All Days Worked:  " + daysWorkedOutput.rstrip(", "))
                daysValidText = "Days Valid: " + str(self.centerList[i].totalValid)
                if self.centerList[i].totalValid > 0:
                    daysValidText += " (" + daysValidOutput.rstrip(", ") + ")"
                daysValidLabel = QtGui.QLabel (daysValidText)
                daysInvalidText = "Days Invalid: " + \
                    str(self.centerList[i].totalWorked -self.centerList[i].totalValid)
##                if (self.centerList[i].totalWorked - self.centerList[i].totalValid) > 0:
##                    daysInvalidText += " (" + daysInvalidOutput.rstrip(", ") + ")"
                daysInvalidLabel = QtGui.QLabel (daysInvalidText)
                personalDaysLabel = QtGui.QLabel("Personal Days Used:" + \
                                        str(self.centerList[i].numPersonalDaysUsed))
                daysNotPaidLabel = QtGui.QLabel("Total Days Not Paid:" + \
                                        str(self.centerList[i].totalDaysNotPaid))

                self.reportOutput += daysValidText + "    "
##                self.reportOutput += daysInvalidText + "    "
                self.reportOutput += "Personal Days Used in" + \
                        str(MONTHS[self.reportMonth-1]) + ":" + \
                        str(self.centerList[i].numPersonalDaysUsed) + "<br>"
                self.reportOutput += "Personal Days Used in" + \
                        str(self.reportYear) + ":" + \
                        str(self.centerList[i].totalLeaveYear) + "<br>"
                self.reportOutput += "Total Days Not Paid: " + \
                        str(self.centerList[i].totalDaysNotPaid) + "    "
                self.reportOutput += "<br>"

                centerHbox = QtGui.QHBoxLayout()
#                centerHbox.addWidget(daysWorkedLabel)
                centerHbox.addWidget(daysValidLabel)
                centerHbox.addWidget(daysInvalidLabel)
                centerHbox.addWidget(personalDaysLabel)
                centerHbox.addWidget(daysNotPaidLabel)

                centerVbox.addLayout(centerHbox)

            payLabel = QtGui.QLabel("Total Monthly Pay:     %.2f<br>" % self.centerList[i].pay)
            centerVbox.addWidget(payLabel)
            self.reportOutput += "Total Monthly Pay:     %.2f<br>" % self.centerList[i].pay
            self.reportOutput += "<p>"

##        wordButton = QtGui.QPushButton("Create Report in Word!")
##        QtCore.QObject.connect(wordButton, QtCore.SIGNAL("clicked()"), self.create_word_document)

        vbox = QtGui.QVBoxLayout()
        vbox.setMargin(15)
        vbox.addWidget(reportTitle)
        vbox.addWidget(notRequiredTitle)
        vbox.addWidget(daysRequiredTitle)
        vbox.addWidget(basePayTitle)

        vbox.addLayout(centerVbox)
        vbox.addStretch(1)
#        vbox.addWidget(wordButton)
        self.w.setLayout(vbox)

        for i in range(len(self.centerList)):
            if len(self.centerList[i].imageList) > 0:
                # if no days worked at center, then skip report
                logger.debug("Creating report for center '%s'" % self.centerList[i].name)
                self.statusBar().showMessage(self.tr("Creating report for " + self.centerList[i].name), 5000)
                self.create_teacher_document(self.centerList[i])

    def view_communityReport(self):
        pass

    def create_block_document(self):
        pass
        #  see notes.txt

    def create_teacher_document(self, teacher):

        doc     = Document()
        ss      = doc.StyleSheet
        ps = ParagraphStyle('Body', TextStyle(TextPS(ss.Fonts.Arial, 18)), \
                            ParagraphPS(space_before=100, space_after=100))
        ss.ParagraphStyles.append(ps)
        p_head = ParagraphStyle('Header', TextStyle( TextPS(font=ss.Fonts.Arial, size=18) ),
                                ParagraphPS(alignment=ParagraphPS.CENTER, space_before = 0, space_after = 0) )
        ss.ParagraphStyles.append(p_head)
        section = Section()
        doc.Sections.append( section )

        # try:
        #     image = Image( "images/seva.png", width=100)
        #     table = Table( TabPS.DEFAULT_WIDTH * 3, TabPS.DEFAULT_WIDTH * 7, TabPS.DEFAULT_WIDTH * 3)
        #     c1 = Cell( Paragraph( ss.ParagraphStyles.Header, LINE, image , ParagraphPS (alignment=ParagraphPS.LEFT)) )
        #     c2 = Cell( Paragraph( ss.ParagraphStyles.Header, LINE, 'Old Fatehpura, Udaipur-313004, Rajasthan, India', LINE,
        #                           ParagraphPS (alignment=ParagraphPS.CENTER)))
        #     c3 = Cell( Paragraph( '' ) )
        #     table.AddRow( c1, c2, c3 )
        #     section.Header.append (table)
        # except Exception as e:
        #     raise Exception("Unable to create header: %s" % e)
        p = Paragraph( "Page ", PAGE_NUMBER, " of ", SECTION_PAGES, ParagraphPS (alignment=ParagraphPS.CENTER) )
        section.Footer.append( p )

##        # changes what is now the default style of Heading1 back to Normal
##        p = Paragraph( ss.ParagraphStyles.Normal, ParagraphPS (alignment=ParagraphPS.RIGHT))
##        today = date.today()
##        p.append( LINE, today.strftime("%A, %d %B %Y") )
##        section.append( p )

##        section.append( Paragraph( Image( "images/seva.png", width=1*72 ) ))

        para_props = ParagraphPS( tabs = [ TabPS( section.TwipsToRightMargin(),
                                              alignment = TabPS.RIGHT,
                                              leader    = TabPS.THICK_LINE  ) ] )
        p = Paragraph( ss.ParagraphStyles.Body, para_props )
        p.append (TAB)
        section.append( p )

        p = Paragraph( ss.ParagraphStyles.Body )
        p.append(TEXT ("Shiksha Kendra Instructor Payment Sheet", bold=True, size=22))
        section.append( p )

        para_props = ParagraphPS( tabs = [ TabPS( width=TabPS.DEFAULT_WIDTH * 3 ),
                                           TabPS( width=TabPS.DEFAULT_WIDTH * 3 ),
                                           TabPS( width=TabPS.DEFAULT_WIDTH * 3 )] )

        try:
            centre = self.code_list[[id[0] for id in self.code_list].index(teacher.name)]
        except:
            self.statusBar().showMessage(self.tr("Cannot find teacher \"" + teacher.name + "\" in code list."), 5000)
            centre = ["","","","","",""]
        p = Paragraph( ss.ParagraphStyles.Body, para_props)
        p.append("Month:         ", TAB, str(MONTHS[self.reportMonth-1]), TAB, "Year:", TAB, str(self.reportYear), LINE)
        now = datetime.now()
        p.append("Date of Issue:", TAB, now.strftime("%B %d, %Y"), LINE)
        p.append("Name of Instructor", TAB, str(centre[5]),LINE)
        p.append("Center ID:     ", TAB, teacher.name, LINE)
        p.append(LINE, TEXT ("Center Information", bold=True, size=20),LINE)
        p.append("Block:        ", TAB, str(centre[1]), TAB, \
                 "Village:      ", TAB, str(centre[3]), LINE)

        p.append("Zone:         ", TAB, str(centre[2]), TAB, \
                 "Hamlet:       ", TAB, str(centre[4]), LINE)
        p.append(LINE, TEXT ("Payment Details", bold=True, size=20),LINE)
        p.append("Days Worked:               ", TAB, "%d" % (teacher.totalValid - self.numTrainingDays), LINE)
#                 "Days Not Paid:  ", TAB, "%d" % teacher.totalDaysNotPaid, LINE)
        p.append("Meeting/Training Attended: ", TAB, "+ %d" % self.numTrainingDays, LINE)
        p.append("Allowed Holidays:          ", TAB,
                 "+ " + str(self.numHolidaysOff[self.reportMonth-1]), LINE)
        p.append("Personal Leave:            ", TAB, "+ %d" % teacher.numPersonalDaysUsed, LINE)
        valid = teacher.totalValid + \
                self.numHolidaysOff[self.reportMonth-1] + teacher.numPersonalDaysUsed
        p.append("Total Valid Days:          ", TAB, TAB, "%d" % valid, LINE)
        p.append("Total Payment:             ", TAB, TEXT ("%.0f" % teacher.pay, bold=True), " Rs.", LINE)
#                 "Amount Lost:      ", TAB, "%.0f Rs." % (self.basePayValue - teacher.pay ), LINE)
##        p.append("Days Invalid: ", TAB,
##            str(teacher.totalWorked - teacher.totalValid) + " days ", LINE)

        p.append(LINE)
        p.append("Leave Remaining in Year:", TAB, TAB, \
                 "%d days" % (self.numPersonalDaysYear - teacher.totalLeaveYear), LINE)

        section.append(p)

        ps = ParagraphStyle('Body2', TextStyle(TextPS(ss.Fonts.Arial, 16)), \
                            ParagraphPS(alignment=ParagraphPS.LEFT, space_before = 10, space_after = 10))
        ss.ParagraphStyles.append(ps)

        thin_edge  = BorderPS( width=20, style=BorderPS.SINGLE )
        thin_frame  = FramePS( thin_edge,  thin_edge,  thin_edge,  thin_edge )
        cSize = 1300
        table = Table (cSize, cSize, cSize, cSize, cSize, cSize, cSize)
        c1 = Cell( Paragraph( ss.ParagraphStyles.Body2, \
                              'Monday' ), thin_frame )
        c2 = Cell( Paragraph( 'Tuesday' ), thin_frame )
        c3 = Cell( Paragraph( 'Wednesday' ), thin_frame )
        c4 = Cell( Paragraph( 'Thursday' ), thin_frame )
        c5 = Cell( Paragraph( 'Friday' ), thin_frame )
        c6 = Cell( Paragraph( 'Saturday' ), thin_frame )
        c7 = Cell( Paragraph( 'Sunday' ), thin_frame )
        table.AddRow( c1, c2, c3, c4, c5, c6, c7 )

        dayCount = 1
        # get the first day of the week for the calendar
        start = date(self.reportYear, self.reportMonth, 1).weekday()
        c = range(7) # cell list

        ps = ParagraphStyle('Body3', TextStyle(TextPS(ss.Fonts.Arial, 16)), \
                            ParagraphPS(alignment=ParagraphPS.LEFT, space_before = 10, space_after = 10))
        ss.ParagraphStyles.append(ps)

        for week in range(6):
            for dayofWeek in range(0, start):
                # display blank days until first day of month
                c[dayofWeek] = Cell( Paragraph (' '), thin_frame)
            for dayofWeek in range(start, 7):
                # display date in table
                if dayCount < self.maxDays + 1:
                    if teacher.daysValid[dayCount-1]:
                        key = "W"
                    elif teacher.daysWorked[dayCount-1]:
                        key = "I"
                    else:
                        key = "OFF"
                    c[dayofWeek] = Cell( Paragraph \
                        (ss.ParagraphStyles.Body3, \
                                str(dayCount), LINE, LINE, key), thin_frame)
                    dayCount += 1
                else:
                    c[dayofWeek] = Cell( Paragraph (ss.ParagraphStyles.Body, \
                                        ss.ParagraphStyles.Body, ' '), thin_frame)
                # after first week, display all dates starting at Monday
                start = 0
##            for i in range(7):
##                print "c[",i,"] = ",c[i]
            table.AddRow( c[0], c[1], c[2], c[3], c[4], c[5], c[6])

        section.append(table )

        p = Paragraph (ss.ParagraphStyles.Body)
        p.append(TAB, TAB, TAB, "Key:", TAB, "W - Day worked, I - Invalid day, Off - Day off", LINE)
        section.append ( p )

        para_props = ParagraphPS( tabs = [ TabPS( section.TwipsToRightMargin(),
                                              alignment = TabPS.RIGHT,
                                              leader    = TabPS.THICK_LINE  ) ] )
        p = Paragraph( ss.ParagraphStyles.Body, para_props )
        p.append(LINE, "Comments:", TAB, LINE,
                 "", TAB, LINE,
                 "", TAB, LINE,
                 "", TAB, LINE)
        section.append( p )

        para_props = ParagraphPS( tabs = [ TabPS( section.TwipsToRightMargin(),
                                              alignment = TabPS.RIGHT,
                                              leader    = TabPS.DOTS  ) ] )
        p = Paragraph( ss.ParagraphStyles.Body, para_props )
        p.append (LINE, LINE, LINE, LINE, LINE, LINE, "Signed:", TAB)
        section.append( p )

        section.append (Paragraph (LINE, LINE, "Date:____________", LINE))

        logger.debug("path: %s" % os.getcwd())
        if os.path.exists("Reports"):
            fileName = "Reports/NFE report " + teacher.name + " "+ str(self.reportMonth)+"-" + \
                    str(self.reportYear) + ".doc"
        else:
            fileName = QtGui.QFileDialog.getSaveFileName(self, "Save Report As", \
                          "NFE report " + teacher.name + " "+str(self.reportMonth)+"-" + \
                                str(self.reportYear) + ".doc", "Documents (*.doc *.rtf)")
        DR = Renderer()

        try:
            DR.Write(doc, file( fileName, "w" ) )
            self.statusBar().showMessage(self.tr("File saved to '%s'" % fileName), 5000)
        except:
            self.statusBar().showMessage(self.tr("File already open.  Unable to save."), 5000)

#===========================END REPORT FUNCTIONS============================================

    def setCurrentFile(self, fileName):
        self.dataFile = fileName
        self.windowModified = False

        if self.dataFile.isEmpty():
            shownName = ""
        else:
            shownName = self.strippedName(self.dataFile)

        self.setWindowTitle("Attend 2.1 - " + MONTHS[self.reportMonth-1] + " " + str(self.reportYear) + " - " + str(shownName))

    def strippedName(self, fullFileName):
        return QtCore.QFileInfo(fullFileName).fileName()

    def open(self):
        if self.maybeSave():
            fileName = QtGui.QFileDialog.getOpenFileName(self, "Select file to load data", "data")
            if not fileName.isEmpty():
                self.load_data(fileName)
            self.verification_overview()

    def save(self):
        if self.dataFile.isEmpty():
            return self.saveAs()
        else:
            return self.save_data(self.dataFile)

    def saveAs(self):
        fileName = QtGui.QFileDialog.getSaveFileName(self, "Save Data As", \
                              "data/" + str(self.reportYear) + MONTHS[self.reportMonth-1] \
                                                     + "data.txt", "Text file (*.txt)")
        if fileName.isEmpty():
            return False
        return self.save_data(fileName)

    def maybeSave(self):
        if self.windowModified:
            ret = QtGui.QMessageBox.warning(self, self.tr("Application"),
                        self.tr("You have loaded image data.\n"
                                "Do you want to save your changes?"),
                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.Default,
                        QtGui.QMessageBox.No,
                        QtGui.QMessageBox.Cancel | QtGui.QMessageBox.Escape)
            if ret == QtGui.QMessageBox.Yes:
                return self.save()
            elif ret == QtGui.QMessageBox.Cancel:
                return False
        return True

    def closeEvent(self, event):
        if self.maybeSave():
#            self.writeSettings()
            event.accept()
        else:
            event.ignore()

    def about(self):
#        self.infoLabel.setText(self.tr("Invoked <b>Help|About</b>"))
        QtGui.QMessageBox.about(self, self.tr("About Attend 2.1"),
                self.tr("<b>Attend 2.1</b> is a program  by Nicholas Shelly for the MIT Abdul Latif Jameel Poverty Action Lab. \
                        Attend helps to record and award teacher attendance at schools across the world. \
                        Copyright &copy; 2010"))

    def createActions(self):
        self.openAct = QtGui.QAction(QtGui.QIcon("images/open.png"),  "&Open Project", self)
        self.openAct.setShortcut(self.tr("Ctrl+O"))
        self.openAct.setStatusTip(self.tr("Open a new folder with photos"))
        self.connect(self.openAct, QtCore.SIGNAL("triggered()"), self.get_directory)

        self.saveAct = QtGui.QAction(QtGui.QIcon("images/save.png"), "&Save Data", self)
        self.saveAct.setShortcut(self.tr("Ctrl+S"))
        self.saveAct.setStatusTip(self.tr("Save the data to disk"))
        self.connect(self.saveAct, QtCore.SIGNAL("triggered()"), self.save)

        self.saveAsAct = QtGui.QAction(self.tr("Save &As..."), self)
        self.saveAsAct.setStatusTip(self.tr("Save the document under a new name"))
        self.connect(self.saveAsAct, QtCore.SIGNAL("triggered()"), self.saveAs)

        self.centerAct = QtGui.QAction(QtGui.QIcon("images/query.png"), "Photo &Verification", self)
        self.centerAct.setShortcut(self.tr("Ctrl+V"))
        self.centerAct.setStatusTip(self.tr("Verify photos from center"))
        self.connect(self.centerAct, QtCore.SIGNAL("triggered()"), self.verification_overview)

        self.configAct = QtGui.QAction(QtGui.QIcon("images/config.png"), "&Configuration", self)
        self.configAct.setShortcut(self.tr("Ctrl+C"))
        self.configAct.setStatusTip(self.tr("Edit the configuration"))
        self.connect(self.configAct, QtCore.SIGNAL("triggered()"), self.configuration_overview)

        self.reportAct = QtGui.QAction(QtGui.QIcon("images/update.png"), "&Reports", self)
        self.reportAct.setShortcut(self.tr("Ctrl+R"))
        self.reportAct.setStatusTip(self.tr("Create or view reports"))
        self.connect(self.reportAct, QtCore.SIGNAL("triggered()"), self.reports_overview)

##        self.printAct = QtGui.QAction(self.tr("&Print..."), self)
##        self.printAct.setShortcut(self.tr("Ctrl+P"))
##        self.printAct.setStatusTip(self.tr("Print the document"))
##        self.connect(self.printAct, QtCore.SIGNAL("triggered()"), self.print_)

        self.exitAct = QtGui.QAction(self.tr("E&xit"), self)
        self.exitAct.setShortcut(self.tr("Ctrl+Q"))
        self.exitAct.setStatusTip(self.tr("Exit the application"))
        self.connect(self.exitAct, QtCore.SIGNAL("triggered()"), QtGui.qApp, QtCore.SLOT("quit()"))

        self.aboutAct = QtGui.QAction(self.tr("&About Attend"), self)
        self.aboutAct.setStatusTip(self.tr("Show the application's About box"))
        self.connect(self.aboutAct, QtCore.SIGNAL("triggered()"), self.about)

    def createMenus(self):
        self.fileMenu = self.menuBar().addMenu(self.tr("&File"))
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addAction(self.saveAsAct)

        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)
##        self.fileMenu.addAction(self.openAct)
##        self.fileMenu.addAction(self.saveAct)
##        self.fileMenu.addAction(self.printAct)

        self.editMenu = self.menuBar().addMenu(self.tr("&Edit"))
        self.editMenu.addAction(self.centerAct)
        self.editMenu.addAction(self.configAct)
        self.editMenu.addAction(self.reportAct)

        self.helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        self.helpMenu.addAction(self.aboutAct)
#        self.helpMenu.addAction(self.aboutQtAct)

    def createToolbars(self):
        self.editToolBar = QtGui.QToolBar("Edit")
        self.addToolBar(QtCore.Qt.BottomToolBarArea, self.editToolBar)
        self.editToolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon)

        self.editToolBar.addAction(self.openAct)
        self.editToolBar.addAction(self.centerAct)
        self.editToolBar.addAction(self.configAct)
        self.editToolBar.addAction(self.reportAct)
        self.editToolBar.addAction(self.saveAct)

        iconSize = QtCore.QSize(96, 84)
        iconSize.scale(70, 70, QtCore.Qt.KeepAspectRatio)
        self.editToolBar.setIconSize(iconSize)
#        self.contentsWidget.setMovement(QtGui.QListView.Static)
#        self.editToolBar.setMaximumWidth(128)
#        self.editToolBar.setMinimumHeight()
#        self.editToolBar.setSpacing(12)

logger.debug(NEW_LOG_SESSION)
app = QtGui.QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.show()
sys.exit(app.exec_())
